package cz.muni.fi.pv112.cranesimulator.models.scene;

import com.jogamp.opengl.util.texture.Texture;
import com.jogamp.opengl.util.texture.TextureIO;
import cz.muni.fi.pv112.cranesimulator.models.Model;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import static cz.muni.fi.pv112.cranesimulator.utils.handlers.opengl.DisplayListHandler.storeModelToDisplayList;
import static cz.muni.fi.pv112.cranesimulator.utils.handlers.opengl.TextureHandler.loadTexture;

/**
 *
 * @author Michal Ďuriš
 */
public class Floor extends Model {

    private float width = 0.0f;
    private float height = 0.0f;
    private int itemsCountInWidth = 0;
    private int itemsCountInHeight = 0;

    private List<float[]> verticesList;
    private List<float[]> textureCoordsList;
    private List<float[]> normalCoordsList;

    private String texturePath = "/cz/muni/fi/pv112/cranesimulator/resources/textures/models/skybox/TropicalSunnyDayDown2048.png";
    private Texture texture;

    public Floor(float width, float height, int itemsCountInWidth,
                 int itemsCountInHeight) {
        this.width = width;
        this.height = height;
        this.itemsCountInWidth = itemsCountInWidth;
        this.itemsCountInHeight = itemsCountInHeight;
    }

    public void init(GL gl) {
        try {
            texture = loadTexture(gl, texturePath, true, TextureIO.PNG);
        } catch (IOException ex) {
            //@TODO: Some better exception handling
            System.err.println("Texture load error in class Floor !!! ");
        } finally {
            createFloor();

            displayListID = storeModelToDisplayList(gl.getGL2(),
                    this,
                    texture,
                    GL2.GL_REPEAT,
                    GL2.GL_REPEAT);
        }
    }

    private void createFloor() {
        final float vertexStepInWidth = width / (float) itemsCountInWidth;
        final float vertexStepInHeight = height / (float) itemsCountInHeight;

        final float textureStepInWidth = 1.0f / (float) itemsCountInWidth;
        final float textureStepInHeight = 1.0f / (float) itemsCountInHeight;

        final float halfWidth = width / 2.0f;
        final float halfHeight = height / 2.0f;

        verticesList = new ArrayList<>(itemsCountInWidth * itemsCountInHeight
                * 4);
        textureCoordsList = new ArrayList<>(itemsCountInWidth
                * itemsCountInHeight * 4);
        normalCoordsList = new ArrayList<>(itemsCountInWidth
                * itemsCountInHeight * 4);

        for (int i = 1; i <= itemsCountInHeight; i++) {
            for (int j = 1; j <= itemsCountInWidth; j++) {
                verticesList.add(new float[] {halfWidth - vertexStepInWidth * (j
                    - 1),
                                              0.0f,
                                              halfHeight - vertexStepInHeight
                                              * (i - 1)});

                verticesList.add(new float[] {halfWidth - vertexStepInWidth * j,
                                              0.0f,
                                              halfHeight - vertexStepInHeight
                                              * (i - 1)});

                verticesList.add(new float[] {halfWidth - vertexStepInWidth * j,
                                              0.0f,
                                              halfHeight - vertexStepInHeight
                                              * i});

                verticesList.add(new float[] {halfWidth - vertexStepInWidth * (j
                    - 1),
                                              0.0f,
                                              halfHeight - vertexStepInHeight
                                              * i});

                textureCoordsList.add(new float[] {textureStepInWidth * (j - 1),
                                                   textureStepInHeight * (i - 1)});

                textureCoordsList.add(new float[] {textureStepInWidth * j,
                                                   textureStepInHeight * (i - 1)});

                textureCoordsList.add(new float[] {textureStepInWidth * j,
                                                   textureStepInHeight * i});

                textureCoordsList.add(new float[] {textureStepInWidth * (j - 1),
                                                   textureStepInHeight * i});

                for (int k = 0; k < 4; k++) {
                    normalCoordsList.add(new float[] {0.0f, 1.0f, 0.0f});
                }
            }
        }
    }

    private float[][] transformListToArray(List<float[]> list) {
        float[][] array = new float[list.size()][3];

        for (int i = 0; i < list.size(); i++) {
            array[i] = list.get(i);
        }

        return array;
    }

    @Override
    public float[][] getVertexCoords() {

        return transformListToArray(verticesList);
    }

    @Override
    public float[][] getTextureCoords() {
        return transformListToArray(textureCoordsList);
    }

    @Override
    public float[][] getNormalCoords() {
        return transformListToArray(normalCoordsList);
    }

    public void setTexturePath(String texturePath) {
        this.texturePath = texturePath;
    }

    public Texture getTexture() {
        return texture;
    }

}
